package util

import (
	"bytes"
	"errors"
	"fmt"
	"image"
	"image-server/config"
	"image/gif"
	"image/jpeg"
	"image/png"
	"io"
	"strings"
	"time"

	"github.com/disintegration/imaging"
	"golang.org/x/image/webp"
)

// 支持的图片格式
const (
	MIMEJPEG = "image/jpeg"
	MIMEPNG  = "image/png"
	MIMEGIF  = "image/gif"
	MIMEWebP = "image/webp"
)

// 自定义错误类型
var (
	ErrInvalidParam = errors.New("无效的参数")
)

// GenerateUserRootFolder 生成用户根文件夹路径
func GenerateUserRootFolder(userID int64, wpsID string) (string, error) {
	if userID <= 0 {
		return "", fmt.Errorf("%w: 无效的用户ID", ErrInvalidParam)
	}
	if wpsID == "" {
		return "", fmt.Errorf("%w: wpsid不能为空", ErrInvalidParam)
	}
	return fmt.Sprintf("image-server/%d_%s/", userID, wpsID), nil
}

// GenerateUserAlbumFolder 生成用户相册文件夹路径
func GenerateUserAlbumFolder(userID int64, wpsID, albumName string) (string, error) {
	if albumName == "" {
		return "", fmt.Errorf("%w: 相册名称不能为空", ErrInvalidParam)
	}
	userRoot, err := GenerateUserRootFolder(userID, wpsID)
	if err != nil {
		return "", err
	}
	safeAlbumName := strings.ReplaceAll(albumName, "/", "_")
	return fmt.Sprintf("%s%s/", userRoot, safeAlbumName), nil
}

// GenerateImageOSSKey 生成图片存储路径
func GenerateImageOSSKey(userID int64, wpsID, albumName, filename string) (string, error) {
	if filename == "" {
		return "", fmt.Errorf("%w: 文件名不能为空", ErrInvalidParam)
	}
	albumFolder, err := GenerateUserAlbumFolder(userID, wpsID, albumName)
	if err != nil {
		return "", err
	}
	timestamp := time.Now().UnixNano()
	return fmt.Sprintf("%s%d-%s", albumFolder, timestamp, filename), nil
}

// GetFileTypeBySuffix 根据文件后缀获取文件类型
func GetFileTypeBySuffix(filename string) string {
	if strings.HasSuffix(filename, ".jpg") || strings.HasSuffix(filename, ".jpeg") {
		return MIMEJPEG
	} else if strings.HasSuffix(filename, ".png") {
		return MIMEPNG
	} else if strings.HasSuffix(filename, ".gif") {
		return MIMEGIF
	} else if strings.HasSuffix(filename, ".webp") {
		return MIMEWebP
	}
	return "" // 未知格式
}

// GenerateTempImageOSSKey 简化版：根据相册ID查询路径，拼接图片名称生成OSS路径
func GenerateTempImageOSSKey(albumID int64, fileName string) (string, error) {
	// 1. 参数校验
	if albumID <= 0 {
		return "", fmt.Errorf("%w: 无效的相册ID", ErrInvalidParam)
	}
	if fileName == "" {
		return "", fmt.Errorf("%w: 文件名不能为空", ErrInvalidParam)
	}

	// 2. 查询相册的OSS路径（从数据库获取album.folder_path）
	var albumFolder string
	err := config.DB.QueryRow(
		"SELECT folder_path FROM albums WHERE id = ?",
		albumID,
	).Scan(&albumFolder)

	if err != nil {
		return "", fmt.Errorf("查询相册路径失败: %w", err)
	}
	if albumFolder == "" {
		return "", errors.New("相册路径不存在")
	}

	// 3. 生成唯一文件名（时间戳+原始文件名，避免重复）
	timestamp := time.Now().UnixNano()
	uniqueFileName := fmt.Sprintf("%d-%s", timestamp, fileName)
	// 4. 拼接完整OSS路径（相册路径 + 唯一文件名）
	return fmt.Sprintf("%s%s", albumFolder, uniqueFileName), nil
}

// 解码不同格式的图片
func decodeImage(content []byte, fileType string) (image.Image, error) {
	switch fileType {
	case MIMEJPEG:
		return jpeg.Decode(bytes.NewReader(content))
	case MIMEPNG:
		return png.Decode(bytes.NewReader(content))
	case MIMEGIF:
		return gif.Decode(bytes.NewReader(content))
	case MIMEWebP:
		return webp.Decode(bytes.NewReader(content))
	default:
		return nil, fmt.Errorf("不支持的图片格式: %s", fileType)
	}
}

// 编码不同格式的图片
func encodeImage(img image.Image, w io.Writer, fileType string) error {
	switch fileType {
	case MIMEJPEG:
		return jpeg.Encode(w, img, &jpeg.Options{Quality: 80})
	case MIMEPNG:
		return png.Encode(w, img)
	case MIMEGIF:
		return gif.Encode(w, img, &gif.Options{NumColors: 256})
	default:
		return fmt.Errorf("不支持的图片格式: %s", fileType)
	}
}

// GenerateThumbnail 生成缩略图（支持保留原图格式）
func GenerateThumbnail(original []byte, width, height int, fileType string) ([]byte, error) {
	if fileType == "" {
		return nil, fmt.Errorf("%w: 图片格式不能为空", ErrInvalidParam)
	}
	// 解码原图
	img, err := decodeImage(original, fileType)
	if err != nil {
		return nil, fmt.Errorf("解码原图失败: %w", err)
	}
	// 生成缩略图（保持比例）
	thumb := imaging.Thumbnail(img, width, height, imaging.Lanczos)

	var buf bytes.Buffer
	if err := encodeImage(thumb, &buf, fileType); err != nil {
		return nil, fmt.Errorf("编码缩略图失败: %w", err)
	}
	return buf.Bytes(), nil
}
